package jdh.util.generic;

import java.lang.reflect.ParameterizedType;
import java.util.List;

import javax.persistence.EntityManager;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Order;

import jdh.util.db.transacao.JPAUtil;

public class GenericDAO<PK, Entidade> implements IGenericDAO<PK, Entidade> {

	private EntityManager entityManager;
	private Class<Entidade> classePersistente;

	@SuppressWarnings("unchecked")
	public GenericDAO() {
		this.entityManager = JPAUtil.getIntance().getEntityManager();
		this.classePersistente = (Class<Entidade>) ((ParameterizedType) this
				.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	}

	@Override
	public void insert(Entidade entidade) {
		this.entityManager.persist(entidade);
	}

	@Override
	public void update(Entidade entidade) {
		this.merge(entidade);
	}

	@Override
	public void delete(Entidade entidade) {
		this.merge(entidade);
		this.entityManager.remove(entidade);
	}

	@Override
	public void deleteById(PK id) {
		StringBuffer nameQuery = new StringBuffer(
				this.classePersistente.getSimpleName() + ".deleteById");

		this.entityManager.createNamedQuery(nameQuery.toString())
				.setParameter("id", id).executeUpdate();
	}

	@Override
	public void merge(Entidade entidade) {
		this.entityManager.merge(entidade);
	}

	@Override
	public void refresh(Entidade entidade) {
		this.entityManager.refresh(entidade);
	}

	@Override
	public void flush() {
		this.entityManager.flush();
	}

	@Override
	public void clear() {
		this.entityManager.clear();
	}

	@Override
	public Entidade findById(PK id) {
		Entidade entidade = null;
		try {
			entidade = this.entityManager.find(this.classePersistente, id);
		} catch (RuntimeException re) {
			re.printStackTrace();
		}
		return entidade;
	}

	@Override
	@SuppressWarnings("unchecked")
	public List<Entidade> search(Entidade entidade, Order... ordenacoes) {
		Criteria criteria = this.criaCriteria().add(criaExemplo(entidade));

		if (ordenacoes != null) {
			for (int i = 0; i < ordenacoes.length; i++) {
				criteria.addOrder(ordenacoes[i]);
			}
		}
		return (List<Entidade>) criteria.list();
	}

	@Override
	@SuppressWarnings("unchecked")
	public List<Entidade> search(Entidade objeto, Integer indiceInicial,
			Integer indiceFinal, Order... ordenacoes) {
		Criteria criteria = criaCriteria().add(criaExemplo(objeto));
		criteria.setFirstResult(indiceInicial);
		criteria.setMaxResults(indiceFinal);

		for (int i = 0; i < ordenacoes.length; i++) {
			criteria.addOrder(ordenacoes[i]);
		}

		return (List<Entidade>) criteria.list();
	}

	@Override
	public int numRows() {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public List<Entidade> findAll(Order... ordenacoes) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public List<Entidade> findAll(Integer indiceInicial, Integer indiceFinal,
			Order... ordenacoes) {
		// TODO Auto-generated method stub
		return null;
	}

	private Example criaExemplo(Entidade objeto) {
		return null;
	}

	private Criteria criaCriteria() {
		Session session = (Session) this.entityManager.getDelegate();
		return session.createCriteria(this.getClassePersistente());
	}

	private Class<Entidade> getClassePersistente() {
		return this.classePersistente;
	}

}
